import { Component, OnDestroy } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { Subscription } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';

import { AlertError } from './alert-error.model';
import { Alert, AlertService } from 'app/core/util/alert.service';
import { EventManager, EventWithContent } from 'app/core/util/event-manager.service';

@Component({
  selector: 'jhi-alert-error',
  templateUrl: './alert-error.component.html',
})
export class AlertErrorComponent implements OnDestroy {
  alerts: Alert[] = [];
  errorListener: Subscription;
  httpErrorListener: Subscription;

  constructor(private alertService: AlertService, private eventManager: EventManager, translateService: TranslateService) {
    this.errorListener = eventManager.subscribe('jhipsterSampleApplicationApp.error', (response: EventWithContent<unknown> | string) => {
      const errorResponse = (response as EventWithContent<AlertError>).content;
      this.addErrorAlert(errorResponse.message, errorResponse.key, errorResponse.params);
    });

    this.httpErrorListener = eventManager.subscribe(
      'jhipsterSampleApplicationApp.httpError',
      (response: EventWithContent<unknown> | string) => {
        const httpErrorResponse = (response as EventWithContent<HttpErrorResponse>).content;
        switch (httpErrorResponse.status) {
          // connection refused, server not reachable
          case 0:
            this.addErrorAlert('Server not reachable', 'error.server.not.reachable');
            break;

          case 400: {
            const arr = httpErrorResponse.headers.keys();
            let errorHeader: string | null = null;
            let entityKey: string | null = null;
            for (const entry of arr) {
              if (entry.toLowerCase().endsWith('app-error')) {
                errorHeader = httpErrorResponse.headers.get(entry);
              } else if (entry.toLowerCase().endsWith('app-params')) {
                entityKey = httpErrorResponse.headers.get(entry);
              }
            }
            if (errorHeader) {
              const alertData = entityKey ? { entityName: translateService.instant(`global.menu.entities.${entityKey}`) } : undefined;
              this.addErrorAlert(errorHeader, errorHeader, alertData);
            } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.fieldErrors) {
              const fieldErrors = httpErrorResponse.error.fieldErrors;
              for (const fieldError of fieldErrors) {
                if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) {
                  fieldError.message = 'Size';
                }
                // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it
                const convertedField: string = fieldError.field.replace(/\[\d*\]/g, '[]');
                const fieldName: string = translateService.instant(
                  `jhipsterSampleApplicationApp.${fieldError.objectName as string}.${convertedField}`
                );
                this.addErrorAlert(`Error on field "${fieldName}"`, `error.${fieldError.message as string}`, { fieldName });
              }
            } else if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) {
              this.addErrorAlert(
                httpErrorResponse.error.detail ?? httpErrorResponse.error.message,
                httpErrorResponse.error.message,
                httpErrorResponse.error.params
              );
            } else {
              this.addErrorAlert(httpErrorResponse.error, httpErrorResponse.error);
            }
            break;
          }

          case 404:
            this.addErrorAlert('Not found', 'error.url.not.found');
            break;

          default:
            if (httpErrorResponse.error !== '' && httpErrorResponse.error.message) {
              this.addErrorAlert(
                httpErrorResponse.error.detail ?? httpErrorResponse.error.message,
                httpErrorResponse.error.message,
                httpErrorResponse.error.params
              );
            } else {
              this.addErrorAlert(httpErrorResponse.error, httpErrorResponse.error);
            }
        }
      }
    );
  }

  setClasses(alert: Alert): { [key: string]: boolean } {
    const classes = { 'jhi-toast': Boolean(alert.toast) };
    if (alert.position) {
      return { ...classes, [alert.position]: true };
    }
    return classes;
  }

  ngOnDestroy(): void {
    this.eventManager.destroy(this.errorListener);
    this.eventManager.destroy(this.httpErrorListener);
  }

  close(alert: Alert): void {
    alert.close?.(this.alerts);
  }

  private addErrorAlert(message?: string, translationKey?: string, translationParams?: { [key: string]: unknown }): void {
    this.alertService.addAlert({ type: 'danger', message, translationKey, translationParams }, this.alerts);
  }
}
